package net.helix.ui.panels.library;

import java.util.ArrayList;
import java.util.List;

import javax.swing.tree.TreePath;

import net.helix.engine.library.Library;
import net.helix.engine.library.LibraryTreeNode;
import net.helix.engine.library.items.LibraryItem;

import org.jdesktop.swingx.treetable.AbstractTreeTableModel;

/**
 * The TreeTableModel that controls most of the library.
 * @author Runouw
 *
 */
public class LibraryTreeTableModel extends AbstractTreeTableModel{
	private LibraryTreeNode root;
	private Library library;
	
	boolean filterCase = false;
	boolean useFilter = false;
	private String filter = "";
	
	public boolean isMouseOver = false;
	//private JXTreeTable treeTable;
	
	public LibraryTreeTableModel(Library library){
		this.library = library;
		this.root = library.getTreeRoot();
	}
	/*
	public void setTreeTable(JXTreeTable treeTable){
		this.treeTable = treeTable;
	}
	*/
	public void setRoot(Library library) {
		this.library = library;
        this.root = library.getTreeRoot();
        
        try{
        	modelSupport.fireNewRoot();
        }catch(Exception e){
        	e.printStackTrace();
        }
    }
	@Override
    public LibraryTreeNode getRoot() {
        return root;
    }
	
	
	
	public int getColumnCount() {
        return 4;
    }

	@Override
    public Class<?> getColumnClass(int column) {
        switch (column) {
        case 0:
            return String.class;
        case 1:
            return String.class;
        case 2:
            return Integer.class;
        case 3:
            return String.class;
        default:
            return super.getColumnClass(column);
        }
    }
	
    @Override
    public String getColumnName(int column) {
        switch (column) {
        case 0:
            return "Name";
        case 1:
            return "Type";
        case 2:
            return "# times used";
        case 3:
            return "Last Edited";
        default:
            return super.getColumnName(column);
        }
    }
    
    public Object getValueAt(Object node, int column) {
        if (node instanceof LibraryTreeNode) {
        	LibraryTreeNode _node = (LibraryTreeNode) node;
            switch (column) {
            case 0:
                return _node.getName();
            case 1:
            	if(_node.id == LibraryTreeNode.FOLDER){
            		return "--";
            	}else{
            		return library.getItem(_node.id).type.name;
            	}
            case 2:
                return 0;
            case 3:
                return "blah";
            }
        }

        return null;
    }
    @Override
    public boolean isCellEditable(Object node, int column) {
    	if (node instanceof LibraryTreeNode) {
        	// LibraryTreeNode _node = (LibraryTreeNode) node;
        	// TODO: if there are any library items that can't have their names edited??
            switch (column) {
            case 0:
                return true;
            default:
            	return false;
            }
        }
    	return false;
    }
    @Override
    public void setValueAt(Object value, Object node, int column){
    	if (node instanceof LibraryTreeNode) {
    		// TODO: check for invalid names? Like if it uses a really odd character...
        	LibraryTreeNode _node = (LibraryTreeNode) node;
            switch (column) {
            case 0:
            	_node.setName((String) value);
            default:
            	
            }
        }
    }
    
    
    @Override
	public int getChildCount(Object parent) {
    	if (parent instanceof LibraryTreeNode) {
    		LibraryTreeNode _parent = (LibraryTreeNode) parent;
    		
    		if(useFilter){
    			int l = _parent.children.size();
    			int sum = 0;
    			for(int i=0;i<l;i++){
    				if(_parent.children.get(i).id == LibraryTreeNode.FOLDER || _parent.children.get(i).getName(!filterCase).contains(filter)){
    					sum++;
    				}
    			}
    			return sum;
    		}else{
    			return _parent.children.size();
    		}
        }
		return 0;
	}
    
    @Override
    public LibraryTreeNode getChild(Object parent, int index) {
    	if (parent instanceof LibraryTreeNode) {
    		LibraryTreeNode _parent = (LibraryTreeNode) parent;
    		if(useFilter){
				int l = _parent.children.size();
    			int position = 0;
    			for(int i=0, h=0;i<l;i++){
    				
    				if(_parent.children.get(i).id == LibraryTreeNode.FOLDER || _parent.children.get(i).getName(!filterCase).contains(filter)){
    					if(h++ == index){
    						position = i;
    						break;
    					}
    					
    				}
    			}
				return _parent.children.get(position);
    		}else{
    			return _parent.children.get(index);
    		}
    	}
    	return null;
    }
    
    @Override
    public boolean isLeaf(Object node) {
        if (node instanceof LibraryTreeNode) {
            return ((LibraryTreeNode) node).id != LibraryTreeNode.FOLDER;
        }
        
        return false;
    }
    
	@Override
	public int getIndexOfChild(Object parent, Object child) {
		if (parent instanceof LibraryTreeNode && child instanceof LibraryTreeNode) {
			LibraryTreeNode _parent = (LibraryTreeNode) parent;
			
			return _parent.children.indexOf(child);
			
		}
		return -1;
	}
	public void setFilter(String newFilter){
		if(!filterCase){
			newFilter = newFilter.toLowerCase();
		}
		
		if(!filter.equals(newFilter)){
			filter = newFilter;
			
			if(filter.equals("")){
				useFilter = false;
			}else{
				useFilter = true;
			}
			/*
			if(treeTable != null){
				// can only drag items around if the search feature is off
				treeTable.setDragEnabled(!useFilter);
			}
			*/
			modelSupport.fireNewRoot();
		}
	}
	public void setFilterCase(boolean b){
		if(b != filterCase){
			filterCase = b;
			setFilter(filter);
			
			modelSupport.fireNewRoot();
		}else{
			filterCase = b;
			setFilter(filter);
		}
		
	}
	public boolean canMoveNodeTo(Object node, Object parent, int index){
		System.out.println("canMoveNodeTo");
		// TODO: check cases where they can't be moved?
		return true;
	}
	
	public void removeNodeFromParent(Object node){
		System.out.println("removeNodeFromParent");
		if (node instanceof LibraryTreeNode) {
			LibraryTreeNode _node = (LibraryTreeNode) node;
			
			
			LibraryTreeNode parent = _node.getParent();
			System.out.println("Node is "+_node.getName());
			
			int index = parent.getIndexOfChild(_node);
			if(parent != null){
				parent.removeNode(_node);
			}
			
			modelSupport.fireChildRemoved(new TreePath(getPathToRoot(parent)), index, _node);
		}
		
		
	}
	public void insertNodeInto(Object node, Object parent, int index){
		System.out.println("insertNodeInto");
		
		if (parent instanceof LibraryTreeNode && node instanceof LibraryTreeNode) {
			LibraryTreeNode _parent = (LibraryTreeNode) parent;
			LibraryTreeNode _node = (LibraryTreeNode) node;
			
			if(_parent.id == LibraryTreeNode.FOLDER){
				_parent.addNodeTo(index, _node);
				
				try{
					modelSupport.fireChildAdded(new TreePath(getPathToRoot(_parent)), index, _node);
				}catch(Exception e){
					e.printStackTrace();
				}
				
			}else{
				LibraryTreeNode _parent2 = _parent.getParent();
				if(_parent2 == null) _parent2 = getRoot();
				_parent2.addNodeTo(index, _node);
				
				modelSupport.fireChildAdded(new TreePath(getPathToRoot(_parent2)), index, _node);
				
			}
			
		}
	}
	
	public void deleteNodeFromParent(Object node){
		System.out.println("removeNodeFromParent");
		if (node instanceof LibraryTreeNode) {
			LibraryTreeNode _node = (LibraryTreeNode) node;
			
			LibraryTreeNode parent = _node.getParent();
			
			if(parent != null){
				System.out.println("Node is "+_node.getName());
				
				int index = parent.getIndexOfChild(_node);
				
				parent.removeNode(_node);
				
				_node.dispose();
				
				modelSupport.fireChildRemoved(new TreePath(getPathToRoot(parent)), index, _node);
			}else{
				_node.dispose();
			}
		}
		
	}
	private ArrayList<LibraryTreeNode> toDeleteList;
	public void deleteNodes(ArrayList<LibraryTreeNode> nodes){
		toDeleteList = new ArrayList<LibraryTreeNode>();
		
		_deleteNodes(new ArrayList<LibraryTreeNode>(nodes));
		
		for(int i=0;i<toDeleteList.size();i++){
			deleteNodeFromParent(toDeleteList.get(i));
		}
	}
	private void _deleteNodes(ArrayList<LibraryTreeNode> nodes){
		for(int i=0;i<nodes.size();i++){
			LibraryTreeNode node = nodes.get(i);
			if(node.id == LibraryTreeNode.FOLDER){
				if(node.getChildCount() > 0){
					_deleteNodes(node.children);
				}
			}
			if(toDeleteList.contains(node) == false){
				toDeleteList.add(node);
			}
		}
	}
	public void addNewFolder(){
		insertNodeInto(new LibraryTreeNode(getRoot().getLibrary(), LibraryTreeNode.FOLDER, "new folder"), getRoot(), 0);
	}
	public void addNewItem(LibraryItem item){
		//int id = getRoot().getLibrary().getNumberOfItems();
		int id = getRoot().getLibrary().addItem(item);
		//item.id = id;
		
		LibraryTreeNode node = new LibraryTreeNode(getRoot().getLibrary(), id, item.name);
		
		LibraryTreeNode parent = getRoot();
		
		insertNodeInto(node, parent, parent.getChildCount());
	}
	public void fireChildAdded(LibraryTreeNode node, int index){
		LibraryTreeNode parent = node.getParent();
		if(parent == null) parent = getRoot();
		
		modelSupport.fireChildAdded(new TreePath(getPathToRoot(node)), index, node);
	}
	
	public LibraryTreeNode[] getPathToRoot(LibraryTreeNode aNode) {
        List<LibraryTreeNode> path = new ArrayList<LibraryTreeNode>();
        LibraryTreeNode node = aNode;

        while (node != root) {
            path.add(0, node);

            node = node.getParent();
        }

        if (node == root) {
            path.add(0, node);
        }

        return path.toArray(new LibraryTreeNode[0]);
    }
	public Library getLibrary(){
		return library;
	}
	
}
